package com.zjh.workflow.flowable.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.zjh.common.exception.ServiceException;
import com.zjh.workflow.flowable.entity.DO.ProcessNodeVariableConfig;
import com.zjh.workflow.flowable.service.IProcessNodeVariableConfigService;
import com.zjh.workflow.flowable.service.ProcessVariableService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class ProcessVariableServiceImpl implements ProcessVariableService {

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private IProcessNodeVariableConfigService processNodeVariableConfigService;

    @Override
    public List<ProcessNodeVariableConfig> getProcessGateWayVariable(String processKey) {
        Map<String, String> variable = extractAllGateWayVariablesFromBpmn(processKey);

        List<ProcessNodeVariableConfig> processVariableConfigs = new ArrayList<>();

        // 设置流程 中的变量值
        variable.forEach((key, value) -> {
            if (StringUtils.isBlank(key)) {
                log.info("key is blank");
                return;
            }
            ProcessNodeVariableConfig item = new ProcessNodeVariableConfig();
            item.setNodeVariable(key);
            item.setProcessKey(processKey);
            item.setNodeName(value);
            processVariableConfigs.add(item);

        });

        return processVariableConfigs;
    }

    @Override
    public Map<String, String> getProcessFirstAssignVariable(String processKey) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processKey)
                .latestVersion()
                .singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        List<Process> processes = bpmnModel.getProcesses();

        Map<String, String> userVariesMap = null;

        // 获取流程定义中的所有元素
        for (Process process : processes) {
            for (FlowElement element : process.getFlowElements()) {

                // 处理用户任务中的分配人变量
                if (element instanceof UserTask) {
                    UserTask userTask = (UserTask) element;
                    userVariesMap = extractAssignmentVariables(userTask);

                    break;
                }
            }
        }

        return userVariesMap;
    }

    @Override
    public List<ProcessNodeVariableConfig> getProcessAssignVariable(String processKey, Boolean skipFirst) {
        Map<String, String> variable = extractAllAssignVariablesFromBpmn(processKey, skipFirst);

        List<ProcessNodeVariableConfig> processVariableConfigs = new ArrayList<>();

        // 设置流程 中的变量值
        variable.forEach((key, value) -> {
            if (StringUtils.isBlank(key)) {
                log.info("key is blank");
                return;
            }

            QueryWrapper<ProcessNodeVariableConfig> wrapper = new QueryWrapper<>();
            wrapper.eq("process_key", processKey);
            wrapper.eq("node_variable", key);

            ProcessNodeVariableConfig one = processNodeVariableConfigService.getOne(wrapper, false);
            if (Objects.isNull(one)) {
                ProcessNodeVariableConfig config = new ProcessNodeVariableConfig();
                config.setProcessKey(processKey);
                config.setNodeVariable(key);
                config.setNodeName(value);
                processNodeVariableConfigService.save(config);
            }

            processVariableConfigs.add(one);

        });

        return processVariableConfigs;
    }


    // 获取所有分配人变量
    public Map<String, String> extractAllAssignVariablesFromBpmn(String processKey, Boolean skipFirst) {

        Map<String, String> res = new HashMap<>();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processKey)
                .latestVersion()
                .singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        List<Process> processes = bpmnModel.getProcesses();

        Map<String, String> userVariesMap = null;

        // 获取流程定义中的所有元素
        for (Process process : processes) {
            for (FlowElement element : process.getFlowElements()) {

                // 处理用户任务中的分配人变量
                if (element instanceof UserTask) {
                    if (skipFirst) {
                        skipFirst = false;
                        continue;
                    }
                    UserTask userTask = (UserTask) element;
                    userVariesMap = extractAssignmentVariables(userTask);
                    res.putAll(userVariesMap);
                }
            }
        }
        return res;
    }

    public Map<String, String> extractAllGateWayVariablesFromBpmn(String processKey) {

        Map<String, String> res = new HashMap<>();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processKey)
                .latestVersion()
                .singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());


        Map<String, String> userVariesMap = null;
        Map<String, String> conditionVariableMap = null;

        // 获取流程定义中的所有元素
        for (Process process : bpmnModel.getProcesses()) {
            for (FlowElement element : process.getFlowElements()) {

                // 处理网关条件表达式中的变量
                if (element instanceof SequenceFlow) {
                    SequenceFlow sequenceFlow = (SequenceFlow) element;
                    conditionVariableMap = extractConditionVariables(sequenceFlow, process);
                    res.putAll(conditionVariableMap);
                }

            }
        }


        return res;

    }

    public Map<String, String> extractAllVariablesFromBpmn(String processKey) {

        Map<String, String> res = new HashMap<>();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processKey)
                .latestVersion()
                .singleResult();

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());


        Map<String, String> userVariesMap = null;
        Map<String, String> conditionVariableMap = null;

        // 获取流程定义中的所有元素
        for (Process process : bpmnModel.getProcesses()) {
            for (FlowElement element : process.getFlowElements()) {

                // 处理用户任务中的分配人变量
                if (element instanceof UserTask) {
                    UserTask userTask = (UserTask) element;
                    userVariesMap = extractAssignmentVariables(userTask);
                    res.putAll(userVariesMap);
                }

                // 处理网关条件表达式中的变量
                if (element instanceof SequenceFlow) {
                    SequenceFlow sequenceFlow = (SequenceFlow) element;
                    conditionVariableMap = extractConditionVariables(sequenceFlow, process);
                    res.putAll(conditionVariableMap);
                }

            }
        }


        return res;

    }

    @Override
    public void saveOrUpdateProcessAssignVariable(ProcessNodeVariableConfig config) {
        QueryWrapper<ProcessNodeVariableConfig> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isBlank(config.getProcessKey()) || StringUtils.isBlank(config.getNodeVariable())) {
            throw new ServiceException("缺少必要参数 ProcessKey NodeVariable");
        }
        queryWrapper.eq("process_key", config.getProcessKey());
        queryWrapper.eq("node_variable", config.getNodeVariable());

        List<ProcessNodeVariableConfig> list = processNodeVariableConfigService.list(queryWrapper);

        // 更新
        if (CollectionUtils.isNotEmpty(list)) {
            processNodeVariableConfigService.update(config, queryWrapper);
        } else {
            processNodeVariableConfigService.save(config);
        }

    }

    @Override
    public void saveOrUpdateBatchProcessAssignVariable(List<ProcessNodeVariableConfig> configs) {
        configs.forEach(this::saveOrUpdateProcessAssignVariable);
    }

    public Map<String, String> extractAssignmentVariables(UserTask userTask) {
        Map<String, String> variables = new HashMap<>();

        // 处理分配人变量
        if (userTask.getAssignee() != null && userTask.getAssignee().startsWith("${")) {
            String varName = userTask.getAssignee().substring(2, userTask.getAssignee().length() - 1);
            variables.put(varName, "任务分配人: " + userTask.getName());
        }

        // 处理候选用户组
        for (String candidateGroup : userTask.getCandidateGroups()) {
            if (candidateGroup.startsWith("${")) {
                String varName = candidateGroup.substring(2, candidateGroup.length() - 1);
                variables.put(varName, "候选用户组: " + userTask.getName());
            }
        }

        // 处理候选用户
        for (String candidateUser : userTask.getCandidateUsers()) {
            if (candidateUser.startsWith("${")) {
                String varName = candidateUser.substring(2, candidateUser.length() - 1);
                variables.put(varName, "候选用户: " + userTask.getName());
            }
        }
        log.info(JSONObject.toJSONString(variables));
        return variables;
    }

    /**
     * 获取条件表达式
     */
    public Map<String, String> extractConditionVariables(SequenceFlow sequenceFlow, Process process) {
        Map<String, String> variables = new HashMap<>();
        if (sequenceFlow.getConditionExpression() != null) {
            String condition = sequenceFlow.getConditionExpression();
            // 简单提取${...}格式的变量
            Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}");
            Matcher matcher = pattern.matcher(condition);
            while (matcher.find()) {
                FlowElement flowElement = process.getFlowElement(sequenceFlow.getSourceFlowElement().getId());
                List<String> strings = extractVariablesFromExpression(matcher.group(1));
                strings.forEach(item -> {
                    variables.put(item, "网关条件: " + flowElement.getName());
                });

            }
        }
        log.info(JSONObject.toJSONString(variables));
        return variables;
    }

    /**
     * 从网关表达式中提取变量
     */
    public List<String> extractVariablesFromExpression(String expression) {
        List<String> variables = new ArrayList<>();

        // 移除所有空格
        String cleaned = expression.replaceAll("\\s+", "");

        // 匹配变量名（更复杂的模式，支持各种运算符）
        Pattern pattern = Pattern.compile("([a-zA-Z_][a-zA-Z0-9_]*)(?=[=<>!+\\-*/]|\\s|$)");
        Matcher matcher = pattern.matcher(cleaned);

        while (matcher.find()) {
            variables.add(matcher.group(1));
        }

        return variables;
    }

}
